package org.smartboot.compare.comparator;

import org.smartboot.compare.ComparatorContext;
import org.smartboot.compare.Option;
import org.smartboot.compare.difference.ComplementSetDifference;
import org.smartboot.compare.difference.Difference;
import org.smartboot.compare.difference.DifferenceGroup;
import org.smartboot.compare.difference.NullOfOneObject;
import org.smartboot.compare.difference.SizeDifference;
import org.smartboot.compare.utils.ComparatorUtils;

import java.util.HashSet;
import java.util.Set;

/**
 * @author qinluo
 * @version 1.0.0
 * @since 2019-05-27 22:53
 */
public class SetComparator extends AbstractComparator<Set<?>> {

    @Override
    public Difference compare(Set<?> expect, Set<?> actual, ComparatorContext<Set<?>> context) {
        if (context.hasOption(Option.LOOSE_MODE) && ComparatorUtils.checkEmpty(expect, actual)) {
            return Difference.SAME;
        }

        //有一个为空
        if (expect == null || actual == null) {
            return new NullOfOneObject(context.getPath(), expect, actual);
        }

        int expectSize = expect.size();
        int actualSize = actual.size();

        DifferenceGroup group = DifferenceGroup.of();

        if (expectSize != actualSize) {
            group.addDifference(new SizeDifference(context.getPath(), expectSize, actualSize, expect, actual));
        }

        if (context.hasOption(Option.IMMEDIATELY_INTERRUPT) && group.hasDifferences()) {
            return group;
        }

        Set<Object> actualComplementSet = new HashSet<>();
        Set<Object> actualCopy = new HashSet<>(actual);

        for (Object key : expect) {
            if (actualCopy.remove(key)) {
                continue;
            }

            actualComplementSet.add(key);
        }

        if (!actualComplementSet.isEmpty() || !actualCopy.isEmpty()) {
            group.addDifference(new ComplementSetDifference(context.getPath(), actualCopy, actualComplementSet));
        }

        return group;
    }
}
